package com.runa.rccprotocol.analysis.langkabo;

import com.alibaba.fastjson.JSON;
import com.runa.monitor.comm.dto.newComm.*;
import com.runa.persistence.RepositoryServicePersis;
import com.runa.persistence.util.LogUtil;
import com.runa.protocol.analysis.ShellBufferAnalysis;
import com.runa.protocol.dto.DtuReport;
import com.runa.protocol.dto.IInterData;
import com.runa.protocol.enums.ByteOrder;
import com.runa.protocol.util.ByteUtil;
import com.runa.rccprotocol.dto.ConcentratorElectric;
import com.runa.rccprotocol.dto.equdata.ConcenReportData;
import com.runa.rccprotocol.dto.equdata.ElectricityMeterData;
import com.runa.rccprotocol.dto.equdata.HeatMeterData;
import com.runa.rccprotocol.dto.equdata.ValveData;
import com.runa.rccprotocol.dto.runa.RunaConcenAffirmDeny;
import com.runa.rccprotocol.dto.runa.RunaConcenResponseData;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;

/**
 * LKB_FMU
 *
 * @author diandian
 * @Date 2022/5/10 19:48
 */
@Slf4j
public class LangKaBoFmuAnalysis extends ShellBufferAnalysis<byte[]> {

    public LangKaBoFmuAnalysis() {
        super(null, 0);
    }

    private String netEquNo;

    @Override
    public int fill(byte[] data, int size, String n) {
//        if (netEquNo!=null)
//            NetEquService.getInstance(msg.getData());
//        this.netEquNo=netEquNo;
        log.debug("{} 收到报文: {}", n, ByteUtil.byteToHexString(data, 0, size));
        this.interData = null;
        int begin = -1;
        short len = -1;
        // 1 注册心跳  2 数据包
        int type = -1;
        for (int i = 0; i < size; i++) {
            if ((data[i] & 0xff) == 0x68 && data[size-1] == 0x16) {
                if ((data[i + 1] & 0xff) == 0x22 || (data[i + 1] & 0xff) == 0x21) {
                    //注册，心跳
                    type = 1;
                    begin = i;
                    len = 4;
                    break;
                } else if ((data[i + 5] & 0xff) == 0x68 && data[size-1] == 0x16) {
                    type = 2;
                    //获取长度
                    short len1 = ByteUtil.byteToShort(data, i + 1, ByteOrder.BA);
                    short len2 = ByteUtil.byteToShort(data, i + 3, ByteOrder.BA);
                    if (len1 == len2) {
                        begin = i;
                        len = len1;
                        break;
                    }
                }
            } else {
                if (data[1] == 3 && data[2] == 0x2c * 2) {
                    RunaConcenResponseData responseData = new RunaConcenResponseData();
                    responseData.addRepData(loraValveData(data));
                    this.interData = responseData;
                    return size - data[2] - 5;
                } else if (data[1] == 6) {
                    this.interData = new RunaConcenAffirmDeny(true);
                }
            }
        }

        if (begin == -1) {
            for (int i = 0; i < size; i++) {
                if ((data[i] & 0xff) == 0x68 && (data[i + 5] & 0xff) == 0x68) {
                    short l = ByteUtil.byteToShort(data, i + 1, ByteOrder.BA);
                    short l2 = ByteUtil.byteToShort(data, i + 3, ByteOrder.BA);
                    if (l != l2) {
                        continue;
                    }
                    if ((i + 6 + l + 2) > size) {
                        return -1;
                    }
                    type = 2;
                    begin = i;
                    len = l;
                    break;
                }
            }
            if (begin == -1) {
                return 0;
            }
        }

        try {
            switch (type) {
                case 1:
                    return handleRegistryOrHeart(data, size, begin, len);
                case 2:
                    return handleEquData(data, size, begin, len);
                default:
            }
        } catch (Exception e) {
//
            log.error("琅卡博报文解析错误: ", e);
            return 0;//消除粘包
        }

        return 0;
    }

    private int handleRegistryOrHeart(byte[] data, int size, int begin, short len) {
        //验证结尾
        byte datum = data[begin + 1 + len + 2];
        if (0x16 != (datum & 0xff)) {
            return size - (begin + 6 + len + 2);
        }
        //校验
        byte check = data[begin + 1 + len + 1];
        if (check != ByteUtil.sum(data, begin, len + 2)) {
//            return size - (begin + 1 + len + 2);
        }

        this.netEquNo = ByteUtil.byteToHexString(data, 2, 4);
        LogUtil.linkDetect(this.netEquNo, "琅卡博", data, begin + 1 + len + 2 + 1, "注册或心跳");

        DtuReport report = new DtuReport(netEquNo);
        report.setMustAck(false);
        this.interData = report;

        return 0;
    }

    private int handleEquData(byte[] data, int size, int begin, short len) {
        //验证结尾
        byte datum = data[begin + 5 + len + 2];
        if (0x16 != (datum & 0xff)) {
            return size - (begin + 6 + len + 2);
        }
        //校验
        byte check = data[begin + 5 + len + 1];
        if (check != ByteUtil.sum(data, begin + 6, len)) {
            return size - (begin + 6 + len + 2);
        }

        if ((data[begin + 1] & 0xff) == 0x24 && (data[begin + 2] & 0xff) == 0x00
                && (data[40] & 0xff) == 0x01) {
            if ((data[41] & 0xff) == 0x01) {
                //换表回复
                this.interData = new RunaConcenAffirmDeny(true);
            } else {
                this.interData = new RunaConcenAffirmDeny(false);
            }
            return 0;
        }

        String serialNo;
//        if ((data[begin + 31] & 0xff) == 0xFF) {
//            begin += 2;
//            serialNo = ByteUtil.byteToHexString(data, begin + 31, 4);
//            if ((data[begin + 30] & 0xff) != 0x78) {
//                String s = ByteUtil.byteToHexString(data[begin + 30]);
//                String replace = s.replace("F", "");
//                serialNo = replace + serialNo;
//            }
//        }else if ((data[begin + 31] & 0xff) == 0x55){
//            begin += 2;
//            serialNo = ByteUtil.byteToHexString(data, begin + 31, 4);
//        }else {
        serialNo = ByteUtil.byteToHexString(data, begin + 31, 4);

        if (serialNo.equalsIgnoreCase("FEFEFEFE")) {//这里为电表数据
            Integer integer = ByteUtil.byteToInt(data, begin + 31 + 18, ByteOrder.DCBA);
            int i = integer - 0x33333333;
            String s = Integer.toHexString(i);
            double electricValue = Float.parseFloat(s) * 0.01;
            ElectricityMeterData meterData = new ElectricityMeterData();
            meterData.setTotal(electricValue);
            RunaConcenResponseData runaConcenResponseData = new RunaConcenResponseData();
            runaConcenResponseData.addRepData(meterData);
            interData = runaConcenResponseData;
            return 0;
        }

        //有的表号不止8位,有可能是9位，或者十位，目前只支持到10位
        if ((data[begin + 30] & 0xff) != 0x78) {
            String s = ByteUtil.byteToHexString(data[begin + 30]);
            String replace = s.replace("7", "");
            serialNo = replace + serialNo;
            if ((data[begin + 29] & 0xff) != 0x56) {
                s = ByteUtil.byteToHexString(data[begin + 29]);
                if (s.startsWith("5")) {
                    serialNo = s.substring(1) + serialNo;
                } else {
                    serialNo = s + serialNo;
                }
            }
        }

        //对比西海岸设备解析的不同点，这里前面是厂家自带的编号
        if (serialNo.startsWith("FFFFF") || serialNo.startsWith("111100")) {
            if (serialNo.startsWith("FFFFF")) serialNo = serialNo.replace("FFFFF", "");
            if (serialNo.startsWith("111100")) serialNo = serialNo.replace("111100", "");
            String s = ByteUtil.byteToHexString(data[begin + 35]) + ByteUtil.byteToHexString(data[begin + 36]);
            serialNo = serialNo + s;
            begin -= 1;
        }


//        }

        //判断是不是阀门
        boolean flagValve = false;
        String equType = ByteUtil.byteToHexString(data, begin + 5 + len - 1, 2);
        if ("2100".equals(equType) || "2200".equals(equType) || "1500".equals(equType)) {
            flagValve = true;
        }

        if (flagValve) {
            ValveVO valveVO = new ValveVO();
//            ValveData valveData = new ValveData();
            valveVO.setReadTime(new Date());
            valveVO.setValveDate(valveVO.getReadTime());
            valveVO.setValveSerial(serialNo);
            int index = 55 + begin;
            Float accHeat = ByteUtil.byteToFloat(data, index, ByteOrder.DCBA);
//            valveData.setAccHeat(accHeat);

            //总开阀时间
            index += 4;
            Float workTime = ByteUtil.byteToFloat(data, index, ByteOrder.DCBA);
            valveVO.setOpenTime((float) 0);

            //总关阀时间
            index += 4;
            Float closeTime = ByteUtil.byteToFloat(data, index, ByteOrder.DCBA);
//            valveData.setOpenValveTime(0);

            //设定温度
            index += 4;
            Short settingTem = ByteUtil.byteToShort(data, index, ByteOrder.BA);
//            valveData.setSetTemperature((float) (settingTem * 0.01));

            //房间温度
            index += 2;
            Short roomTem = ByteUtil.byteToShort(data, index, ByteOrder.BA);
//            valveData.setCurrTemperature((float) (roomTem * 0.01));
            short zero = 0;


            //最大温度
            index += 2;
            double maxTem = ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01;

            //最小温度
            index += 2;
            double minTem = ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01;

            //平均温度
            index += 2;
            double avgTem = ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01;

            //阀门开度
            index += 2;
            int opening = data[index] & 0xff;
            valveVO.setActOpen((float) opening);
//            valveData.setSwitchState(opening != 0);

            //阀门MIN开度
            ++index;
            int minOpening = data[index] & 0xff;
            valveVO.setOpenDL((float) minOpening);

            //阀门MAX开度
            ++index;
            int maxOpening = data[index] & 0xff;
            valveVO.setOpenUL((float) maxOpening);

            //管理员控制权限
            ++index;
            int ctrl = data[index] & 0xff;

            //故障代码
            ++index;
            String faultCode = ByteUtil.byteToHexString(data, index, 2);

            //保留
            index += 2;
            String retain = ByteUtil.byteToHexString(data, index, 5);

            //是否采集成功
            index += 5;
            boolean readResult = ByteUtil.getByBit(data[index], 0) == 1;

            //阀门类型

            AffiliatePanelVO panel = new AffiliatePanelVO(0, 0, (float) (roomTem * 0.01), zero);
            panel.setSerial(valveVO.getValveSerial());
            panel.setReadTime(valveVO.getReadTime());
            //温度带面板使用map
//            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
//            stringObjectHashMap.put("valve",valveVO);
//            stringObjectHashMap.put("panel",panel);
            valveVO.getPanelVOList().add(panel);
            RunaConcenResponseData responseData = new RunaConcenResponseData();
            responseData.setAddress(netEquNo);
            responseData.addRepData(valveVO);
            this.interData = responseData;
            return size - (begin + 6 + len + 2);
        } else {
            HotMeterVO meterData = new HotMeterVO();
            meterData.setMeterSerial(serialNo);

            int index = 55 + begin;
            Float accCloud = ByteUtil.byteToFloat(data, index, ByteOrder.DCBA);

            index += 4;
            meterData.setAccHeat(ByteUtil.byteToFloat(data, index, ByteOrder.DCBA));

            index += 4;
            meterData.setPower(ByteUtil.byteToFloat(data, index, ByteOrder.DCBA));

            index += 4;
            meterData.setAccFlow(ByteUtil.byteToFloat(data, index, ByteOrder.DCBA));

            index += 4;
            meterData.setFlow((ByteUtil.byteToFloat(data, index, ByteOrder.DCBA)));

            index += 4;
            meterData.setSupplyTemp((float) (ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01));

            index += 2;
            meterData.setReturnTemp((float) (ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01));

            if (meterData.getAccHeat()==0 && meterData.getAccFlow()==0
                    && meterData.getPower()==0 && meterData.getFlow()==0
                    && meterData.getSupplyTemp()==0 && meterData.getReturnTemp()==0
            ) return 0;
//            if (meterData.getAccHeat() == 0 && meterData.getAccFlow() == 0 && meterData.getSupplyTemp() == 0) return 0;

            index += 2;
            double diffTemp = ByteUtil.byteToShort(data, index, ByteOrder.BA) * 0.01;

            //故障代码
            index += 2;
            String faultCode = ByteUtil.byteToHexString(data, index, 2);

            //热表运行时间
            index += 2;
            Integer time = ByteUtil.byteToInt(data, index, ByteOrder.DCBA);
            meterData.setWorkTime(time);
            meterData.setReadDate(new Date());
            RunaConcenResponseData responseData = new RunaConcenResponseData();
            responseData.setAddress(netEquNo);
            responseData.addRepData(meterData);
            System.out.println(meterData.toString());
            this.interData = responseData;
//            return size - (begin + 6 + len + 2);
            return 0;
        }
    }

    public ValveVO loraValveData(byte[] data) {
        ValveVO valveData = new ValveVO();
        valveData.setReadTime(new Date());
        valveData.setIndex(data[0] & 0xff);
        int idx = 3;
        valveData.setRemoteSet((float) data[idx]);
        idx += 10;
        int model = data[idx];
        idx += 20;
        switch (model) {
            case 0:
                valveData.setModel(ValveVO.ModelEnum.开度);
                break;
            case 6:
                valveData.setModel(ValveVO.ModelEnum.回温);
                break;
        }
        if (model == 6) {
            valveData.setRemoteSet(Float.valueOf(ByteUtil.byteToShort(data, idx, ByteOrder.BA)) / 100);
        }
        idx += 12;
//        valveData.setOpenTime(Float.valueOf(ByteUtil.byteToInt(data, idx, ByteOrder.DCBA)));
        idx += 4;
        valveData.setValveSerial(String.valueOf(ByteUtil.byteToInt(data, idx, ByteOrder.DCBA)));
        idx += 10;
        valveData.setSoftVersion(ByteUtil.byteToHexString(data[idx]));
        valveData.setHardVersion(ByteUtil.byteToHexString(data[idx + 1]));
        idx += 16;
        int statusCode = ByteUtil.byteToShort(data, idx, ByteOrder.BA);
        valveData.setStatus(ByteUtil.byteToHexString(data, idx, 2));
        ArrayList<String> list = new ArrayList<>();
        if ((statusCode & 1) == 1) {
            list.add("阀门异常");
        }
        if ((statusCode >> 1 & 1) == 1) {
            list.add("蓝牙故障");
        }
        if ((statusCode >> 2 & 1) == 1) {
            list.add("进水故障");
        }
        if ((statusCode >> 3 & 1) == 1) {
            list.add("回水故障");
        }
        if ((statusCode >> 3 & 1) == 1) {
            list.add("回水故障");
        }
        valveData.setFaultCode(list);
        idx += 2;
        valveData.setActOpen(Float.valueOf(ByteUtil.byteToShort(data, idx, ByteOrder.BA)));
        idx += 6;
        valveData.setSupplyTemp((float) (ByteUtil.byteToShort(data, idx, ByteOrder.BA) * 0.01));
        idx += 2;
        valveData.setReturnTemp((float) (ByteUtil.byteToShort(data, idx, ByteOrder.BA) * 0.01));
        idx += 2;
        valveData.setFrontPre((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) * 0.1 / 1000));
        idx += 2;
        valveData.setBehindPre((float) (ByteUtil.byteToUShort(data, idx, ByteOrder.BA) * 0.1 / 1000));
        return valveData;
    }

    public static void main(String[] args) {
//        String s = "6822530200543316";
//        String s = "68 55 00 55 00 68 41 02 37 01 00 00 0C F0 00 00 20 03 00 00 00 01 53 02 02 87 00 12 34 56 78 21 78 40 33 11 11 00 21 78 40 33 E7 24 09 17 30 10 23 24 49 03 31 03 22 00 00 00 00 00 00 24 42 00 00 00 00 E1 7A 14 40 00 00 00 00 53 08 F4 07 00 00 00 00 00 00 00 00 00 01 2E 00 B5 16";
//        String s = "6855005500684102370100000CF0000020030000000163116351001234567831625477111100316254777C161415241123070815241123000000001F851B4000000000EC51B83D00000000A1075309000000000000000000012E00A816";
//        String s = "6855005500684102370100000CF0000020030000000163116040001234567200904552095902009045527658521508122324271408122300000000000000000000000000000000000000004B08DD07000000000000000000011900CE16";
//        String s = "68 31 00 31 00 68 41 02 37 01 00 00 10 F0 00 00 01 00 00 00 00 00 53 02 03 17 00 18 00 00 00 FE FE FE FE 68 88 88 88 88 88 88 68 91 08 33 33 33 33 C9 36 33 33 CA 16 A5 16";
//        String s = "6855005500684102370100000CF0000020030000000163111002001234567831625214111100316252141043042118074939441631012400000000C351824585EB314085CBE3433BDF8F3E7614151100000000B80A000000012E00CC16";
        String s = "F303585F003200E803E803E8030000D002320005003C00010B0A04803EFC080000CC10631400000000000000007C94F8038B725901180C050A2525902802003200B80BF4011E000100B60304C96000000000000000820E000000C08499";
//        String s = "52035833003200E803E803E80300000000320005003C00010B0A04803EFC080000CC10631400000000000000007025EB03CA555901180B0B0B2702862802003200B80BF4011E000100FE0104C83300000000000000470B000000007F8F  ";
//        String meterData = "6855005500684102370100000CF0000020030000000153020367001234567855918107005555559181079B52331017062235291407032200000000F81300000000000000000000AC0DF401F4015F055F0014060000000000112100BE16";
//        String valveData = "6855005500684102370100000CF00000200300000001530202980012345678559126250055555591262599170817230622381513170422000000000000000000000000F00AC409AC0DF401F4015F055F0014060000000000112100DA16";


//        String valveData = "6860006000684102370100000CF000002003000000011234567160466678FFFFF160466678F150271920092200001504172009220000000000000093884700000000EC71204600000000810990090000000000000100000000000000000000000000000000002F16";
//        String valveData = "6855005500684102370100000CF000002003000000015302004100123456783309213000555533092130DF1924182009220000000000000000000000000000000000000000000000000000000000000000000000000000000015009D16";


//        String valveData = "6855005500684102370100000CF00000200300000001530203420012345678559101420055555591014275413420200922301813270622000000009A030000000000009C310000AC0DF401F4015F055F00140600000000001121006016";
//        String valveData = "6860006000684102370100000CF000002003000000011234567140421556FFFFF140421556DA011418290922000037541929092200000000000066FA0D47000000001FE95C4600000000D609FA090000000000000100000000000000000000000000000000000516";
//        String valveData = "6860006000684102370100000CF000002003000000011234567140421543FFFFF140421543DA4321192909220000321620290922000000000000335D6146000000005234504500000000A709B2090000000000000100000000000000000000000000000000007016";

//        String valveData = "6860006000684102370100000CF00000200300000001123456783302929100555533029291DA420714051022000000000000000000000000000000000000000000000000000005001E00000014000000000014500101000000000000000000000000000000001416";
//        String valveData = "681F001F006841023701000000F000000400000000010C0000200300000000B003002000057716";


        LangKaBoFmuAnalysis analysis = new LangKaBoFmuAnalysis();
        byte[] bytes = ByteUtil.hexStringToByte(s);
        int fill = analysis.fill(bytes, bytes.length, "");
        System.out.println(fill + ": " + JSON.toJSONString(analysis.gain()));
    }
}
